package wps.component.elementsetting {
import flash.geom.Matrix;
import flash.geom.Point;

import spark.components.supportClasses.SliderBase;

import wps.skin.SettingCircularSliderSkin;

/**
 * @see http://blog.mediarain.com/2011/06/flex-4-circular-slider/
 * @author Jeremiah
 */
public class SettingCircularSlider extends SettingSliderBase {

    //--------------------------------------------------------------------------
    //
    // Properties
    //
    //--------------------------------------------------------------------------

    private var _thumbHeight:Number = 11;

    [Bindable]
    public function get thumbHeight():Number {
        return _thumbHeight;
    }

    public function set thumbHeight(value:Number):void {
        _thumbHeight = value;
    }

    private var _thumbWidth:Number = 11;

    [Bindable]
    public function get thumbWidth():Number {
        return _thumbWidth;
    }

    public function set thumbWidth(value:Number):void {
        _thumbWidth = value;
    }

    //--------------------------------------------------------------------------
    //
    // Constructor
    //
    //--------------------------------------------------------------------------

    public function SettingCircularSlider() {
        super();

        setStyle("skinClass", Class(SettingCircularSliderSkin));
        width = 25 + 48 + Math.round(thumbWidth / 2) + 3;
    }

    //--------------------------------------------------------------------------
    //
    // Methods
    //
    //--------------------------------------------------------------------------

    override protected function pointToValue(x:Number, y:Number):Number {
        if (!thumb || !track) {
            return 0;
        }

        // find the center of the ellipse
        var center:Point = new Point((track.getLayoutBoundsWidth() - thumb.getLayoutBoundsWidth()) / 2, (track.getLayoutBoundsHeight() - thumb.getLayoutBoundsHeight()) / 2);

        // by default we want to begin at the top so we need to find the top of the ellipse
        var top:Point = new Point(((track.getLayoutBoundsWidth() - thumb.getLayoutBoundsWidth()) / 2) - center.x, -center.y);

        // adjust the x,y coordinates
        var point:Point = new Point(x - center.x, y - center.y);

        var m:Matrix = new Matrix();

        // check if the ellipse is an oval
        if (track.getLayoutBoundsHeight() < track.getLayoutBoundsWidth()) {
            m.scale(track.getLayoutBoundsHeight() / track.getLayoutBoundsWidth(), 1);
        } else if (track.getLayoutBoundsWidth() < track.getLayoutBoundsHeight()) {
            m.scale(1, track.getLayoutBoundsWidth() / track.getLayoutBoundsHeight());
        }

        // calculate the adjusted point if there is any scaling
        point = m.transformPoint(point);

        // calculate the angle between the top of the circle and where the mouse is
        var degrees:Number = (Math.atan2(top.x * point.y - top.y * point.x, top.x * point.x + top.y * point.y)) * (180 / Math.PI);

        // adjust the value to account for what is set as the maximum and minimum
        return (((degrees < 0) ? 360 + degrees : degrees) / (360 / (maximum - minimum))) + minimum;
    }

    override protected function updateSkinDisplayList():void {
        if (!thumb || !track) {
            return;
        }

        // adjust the pending value to account for maximum and minimum
        var pend:Number = ((360 * (pendingValue - minimum)) / (maximum - minimum));

        // make sure the thumb is the correct size
        thumb.height = _thumbHeight;
        thumb.width = _thumbWidth;

        // find the center of the ellipse
        var center:Point = new Point(track.getLayoutBoundsWidth() / 2, track.getLayoutBoundsHeight() / 2);

        // set up a matrix to transform the top of the ellipse based on the angle of rotation
        var m:Matrix = new Matrix();
        m.translate(-center.x, -center.y);
        m.rotate(pend * (Math.PI / 180));
        m.translate(center.x, center.y);

        // find the top of the ellipse
        var top:Point = new Point((track.getLayoutBoundsWidth() / 2), 0);

        // now transform the point based on the rotation
        var p:Point = m.transformPoint(new Point(top.x, top.y));

        // if the ellipse is more of an oval then we need to further adjust the point
        if (track.getLayoutBoundsWidth() > track.getLayoutBoundsHeight() || track.getLayoutBoundsHeight() > track.getLayoutBoundsWidth()) {

            m = new Matrix();
            m.translate(-center.x, -center.y);
            m.scale(track.getLayoutBoundsWidth() / track.getLayoutBoundsHeight(), 1);
            m.translate(center.x, center.y);

            p = m.transformPoint(p);
        }

        // convert to parent's coordinates.
        var thumbPos:Point = track.localToGlobal(p);
        var thumbPosParentX:Number = thumb.parent.globalToLocal(thumbPos).x - (thumb.getLayoutBoundsWidth() / 2);
        var thumbPosParentY:Number = thumb.parent.globalToLocal(thumbPos).y - (thumb.getLayoutBoundsHeight() / 2);

        thumb.setLayoutBoundsPosition(Math.round(thumbPosParentX), Math.round(thumbPosParentY));
    }

}
}
